package org.aurora.remote;

import org.aurora.remote.protocol.RemoteResponse;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public interface SendCallback<RESPONSE extends RemoteResponse> {
    Map<Class<? extends SendCallback>, Class<? extends RemoteResponse>> RESPONSE_TABLE = new ConcurrentHashMap();

    void onSuccess(RESPONSE response);

    void onFail(Throwable e);

    default Class<RESPONSE> getResponseClass() {
        Class<? extends SendCallback> clazz = getClass();

        Class<? extends RemoteResponse> remoteResponseClass = null;
        if ((remoteResponseClass = RESPONSE_TABLE.get(clazz)) == null) {
            synchronized (clazz) {
                if ((remoteResponseClass = RESPONSE_TABLE.get(clazz)) == null) {
                    Method[] declaredMethods = clazz.getDeclaredMethods();

                    for (Method method : declaredMethods) {
                        Class<?>[] parameterTypes = method.getParameterTypes();

                        if ("onSuccess".equals(method.getName()) &&
                                parameterTypes.length == 1 &&
                                parameterTypes[0].getSuperclass() == org.aurora.remote.protocol.RemoteResponse.class) {
                            remoteResponseClass = (Class<? extends RemoteResponse>) parameterTypes[0];
                            break;
                        }
                    }
                    remoteResponseClass = remoteResponseClass == null ? org.aurora.remote.protocol.RemoteResponse.class : remoteResponseClass;
                    RESPONSE_TABLE.put(clazz, remoteResponseClass);
                }
            }
        }

        return (Class<RESPONSE>) remoteResponseClass;
    }
}
